# amplitude.http -- utility module for HTTP handling.
# by Sean A. Harrison <sah@tyndale.com>
# ---------------------------------------------------------------------------
# $Id: http.py 73 2013-03-26 20:07:41Z sah.harrison@gmail.com $

from Cookie import SimpleCookie
from cgi import FieldStorage
from urllib import quote
from amplitude.dict import Dict
from urlparse import parse_qs
from .url import URL

class Request(Dict):
    """holds request information: env, db, session, route, response, etc.
    """
    def __init__(self, env, config, **args):
        """a bunch of convenience shortcuts that get used a lot."""
        Dict.__init__(self, **args)
        self.config = config
        self.DEBUG = config.Site.debug and eval(config.Site.debug) or False
        self.env = Dict(**env)
        self.method = self.env['REQUEST_METHOD']
        self.make_cookie()
        self.make_params()
        self.make_path()
        self.make_uri()             # self.uri as string kept for backward compatibility

    def make_path(self):
        self.path = ''
        if self.env.has_key('PATH_INFO'):
            self.path += self.env['PATH_INFO'].rstrip('/')#.decode('UTF-8')
    
    def make_uri(self):
        env = self.env
        config = self.config
        site_host = config.Site.host.split("://")
        if len(site_host)==1:
            scheme = 'http'
            host = site_host[0]
        else:
            scheme = site_host[0]
            host = site_host[1]
        path = (config.Site.path or '') + (env.get('PATH_INFO') or '')
        query = env.get("QUERY_STRING").split('#')
        qstring = query[0]
        if len(query)>1:
            fragment = query[1]
        else:
            fragment = None
        self.url = URL('', scheme=scheme, host=host, path=path, query=qstring, fragment=fragment)
        self.uri = str(self.url)

    def make_cookie(self):
        """pull cookies out of headers and add to self.cookie"""
        if self.env.get('HTTP_COOKIE'):
            http_cookie = self.env.get('HTTP_COOKIE')
            self.cookie = SimpleCookie()            
            self.cookie.load(http_cookie)

    def make_params(self):
        """pull Field Storage values out of env and add to self.params."""
        if self.env.has_key('wsgi.input'):
            self.params = Dict()
            fs = FieldStorage(
                fp=self.env['wsgi.input'],
                environ=self.env,
                keep_blank_values=True
            )
            for k in fs:
                if type(fs[k]) == list:
                    for i in fs[k]:
                        self.params[k] = (i.value or '')#.decode('UTF8')
                else:
                    self.params[k] = (fs[k].value or '')#.decode('UTF8')

    def init_session(self, session_id=None, session_storage=None, reload=False, **args):
        """initialize req.session"""
        if self.session is None or reload==True:
            self.session_storage = session_storage or self.session_storage
            if session_id is None:
                if self.cookie and self.cookie.has_key('session_id'):
                    session_id = self.cookie.get('session_id').value
            self.session = self.session_storage.init_session(session_id, **args)
            if self.DEBUG==True: print "INIT SESSION:", self.session.id
        
    def reset_session(self):
        """remove the session_id cookie and init a new session."""
        if self.cookie and self.cookie.has_key('session_id'):
            del(self.cookie['session_id'])
        self.session = self.session_storage.init_session()
        self.session.save()

    # convenience functions for http methods
    def GET(self): 
        return self.env['REQUEST_METHOD'] == 'GET'
    def POST(self): 
        return self.env['REQUEST_METHOD'] == 'POST'
    def PUT(self): 
        return self.env['REQUEST_METHOD'] == 'PUT'
    def DELETE(self): 
        return self.env['REQUEST_METHOD'] == 'DELETE'
    def XHR(self): 
        return self.env.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
        
class Response(dict):
    """holds response information: headers, body, output_stream
    >>> r = Response()
    >>> r.status, r.headers, r.body
    ('200 OK', [], [])
    >>> r.set_cookie('sessionid', 'somesecret', path='/')
    >>> r.headers
    [('Set-Cookie', 'sessionid=somesecret; path=/')]
    """

    def __init__(self):
        self.body = []                      # the body of the response.
        self.headers = []                   # headers must be a list of tuples
        self.status = "200 OK"              # default status.
        self.filewrapper = None             # for FileWrapper streaming data.

    def get_header(self, name):
        """gets the current values for the named header. Always returns a list"""
        values = []
        for i in range(len(self.headers)):
            if self.headers[i][0] == name:
                values.append(self.headers[i][1])
        return values
        
    def set_header(self, name, value):
        """sets the value for the named header. Also removes any existing header with that name.
        (Use response.headers.append(...) to append a header).
        Returns None
        If value given is None, clears the header
        """
        # remove any header with the given name
        for i in range(len(self.headers)-1, -1, -1):
            if self.headers[i][0] == name:
                self.headers.pop(i)
        if type(value) in (unicode, str):
            value = value.encode('UTF-8')
        if value is not None:
            self.headers.append((name, value))        

    def set_cookie(self, name, value, domain=None, expires=None, path=None):
        cookie = ["%s=%s" % (name, value)]
        if expires:
            cookie.append("expires=%s" % str(expires))
        if path:
            cookie.append("path=%s" % str(path or '/'))
        if domain:
            cookie.append("domain=%s" % str(domain))
        self.set_header('Set-Cookie', "; ".join(cookie))

    def delete_cookie(self, name, domain=None, path=None):
        self.set_cookie(name, '', domain=domain, path=path)

    def sendfile(self, fileobj, blocksize=8192):
        from wsgiref.util import FileWrapper
        self.filewrapper = FileWrapper(fileobj, blocksize)

    def redirect(self, url):
        if url is not None:
            self.status = "302 Found"
        else:
            self.status = ""
        self.set_header('Location', url)
        #if self.DEBUG==True: print "redirecting to:", url

    def moved(self, url):
        self.status = "301 Moved"
        self.headers += [('Location', url)]

    def unauthorized(self):
        self.status = "401 Unauthorized"
        self.headers += [('Content-Type', 'text/html')]

    def forbidden(self):
        self.status = "403 Forbidden"
        self.headers += [('Content-Type', 'text/html')]

    def not_found(self):
        self.status = "404 Not Found"
        self.headers += [('Content-Type', 'text/html')]
        
    def not_implemented(self):
        self.status = "501 Not Implemented"
        self.headers += [('Content-Type', 'text/html')]

class Context(Dict):
    pass

# ---------------------------------------------------------------------------
if __name__ == '__main__':
    import doctest
    doctest.testmod()
